home *** CD-ROM | disk | FTP | other *** search
- /*
- * Shar puts readable text files together in a package
- * from which they are easy to extract.
- *
- * v 860716 M. Kersenbrock (tektronix!copper!michaelk) for Z80-CPM
- * - enhanced usage message
- *
- * v 860712 D. Wecker for ULTRIX and the AMIGA
- * - stripped down.. does patterns but no directories
- * - added a -u (unshar) switch
- *
- * v 870128 R. Royar for ST
- * - removed #ifdefs that left stray }s in file
- * - reformatted text for consistant style
- * - modified main to abort when no files are given
- * - fixed call to fputc in tell macro, which omitted the stream
- * causing address errors on the ST.
- * - fixed STUPID coding in getopt that tried to write to
- * address 0++.
- * - known bugs:
- * still no directory support. Extracting
- * files with directory names will get
- * only the directory name on an open call.
- *
- * v 880713 J. Altstadt for ST
- * - removed extraneous #ifdefs for all other systems
- * - reformatted text for consistant style
- * - changed lots of things for unsharing:
- * 1. added directory handling
- * 2. added code to handle weird shar sed formats better,
- * will add more things when i get files that i can't unshar,
- * eg. when i get one of those icky sharchives that has split files
- * but won't add in the ability to handle shars that use awk to
- * extract files (yes, windsrch uses awk, blech!!!)
- * 3. added in file overwrite protection, i didn't need it, but it was
- * easy (and i know i will need it some day when i don't have a
- * backup)
- * 4. skip whitespace at begining of lines intended for sh, so it will
- * do stuff embedded in "if test" structures
- *
- * v 890124 J. Altstadt for ST
- * - unshar will handle files split across two (or more) sharchives
- * - fixed bug that would allow creation of directories (files) with
- * the same name as an existing file (directory)
- */
-
-
- #include <stdio.h>
- #include <osbind.h>
- #include <ctype.h>
- #include <stat.h>
-
- long _stksize = 16 * 1024; /* for 10k stack */
- char *Defenv = "ENOENV"; /* if no cc.ini file */
- extern char *getenv(),*malloc(),*index();
- void shar();
-
-
- #define BADCH ((int)'?')
- #define EMSG ""
- #define tell(s) {fputs(*nargv,stderr);fputs((s),stderr);fputc('\n',stderr);}
- #define rescanopts() (optind = 1)
-
- int optind = 1, /* index into parent argv vector */
- optopt; /* character checked for validity */
- long fsize; /* length of file */
- char *optarg; /* argument associated with option */
- char *sav[100]; /* saved file names */
- int savind; /* save index */
-
- /* OPTIONS */
- int Verbose = 0; /* provide append/extract feedback */
- int Basename = 0; /* extract into basenames */
- int Count = 0; /* count characters to check transfer */
- char *Delim = "SHAR_EOF"; /* put after each file */
- char Filter[100] = "cat"; /* used to extract archived files */
- char *Prefix = NULL; /* line prefix to avoid funny chars */
- int OverWrite = 0; /* do we overwrite an output file? */
-
- char Usage1[] =
- "\nSHAR: Create/extract file archive for extraction by /bin/sh (normally).\n\
- \n\
- usage: shar [[-uo] archive] [[-a] [-p prefix]\
- [-d delim] [-bcv] files > archive]\n\
- \n\
- where: -a all the options (v,c,b,-pXX)\n";
-
- char Usage2[] =
- " -b extract absolute paths into current directory\n\
- -c check filesizes on extraction\n\
- -d use this EOF delimiter instead of SHAR_EOF\n";
-
- char Usage3[] =
- " -o unshar <archive>, overwriting old files\n\
- -p use this as prefix to each line in archived files\n\
- -u unshar <archive>, not overwriting old files\n\
- -v verbose on extraction, incl. echoing filesizes\n";
-
-
- #define SED "sed 's/^%s//'" /* used to remove prefix from lines */
- #define OPTSTRING "u:o:ap:d:bcv"
-
-
- void main(argc, argv)
- int argc;
- char **argv;
- {
- char *ppchFiles[256];
- register int C;
- char **ppchList = ppchFiles;
- register int errflg;
- errflg = 0;
-
- while(EOF != (C = getopt(argc, argv, OPTSTRING))) {
- switch(C) {
- case 'v':
- Verbose++;
- break;
- case 'c':
- Count++;
- break;
- case 'b':
- Basename++;
- break;
- case 'd':
- Delim = optarg;
- break;
- case 'a': /* all the options */
- optarg = "X";
- Verbose++;
- Count++;
- Basename++;
- /* fall through to set prefix */
- case 'p':
- sprintf(Filter, SED, Prefix = optarg);
- break;
- case 'o':
- OverWrite++;
- case 'u':
- dounshar(optarg);
- exit(0);
- break;
- default:
- errflg++;
- }
- }
-
- C = getarg(argc, argv);
- if (errflg || EOF == C) {
- if (EOF == C)
- fprintf(stderr, "shar: No input files\n");
- fprintf(stderr, "%s%s%s", Usage1, Usage2, Usage3);
- exit(1);
- }
- savind = 0;
-
- do {
- if (getpat(optarg)) exit(2);
- } while (EOF != (C = getarg(argc, argv)));
-
- sav[savind] = 0;
- header(sav);
- for (ppchList = sav; *ppchList; ++ppchList)
- shar(*ppchList);
- puts("#\tEnd of shell archive");
- puts("exit 0");
- exit(0);
- }
-
-
- int header(ppchFiles)
- char *ppchFiles[];
- {
- char clock[40];
- register char **ppchList;
- char *pchOrg;
- char *pchName;
- register int problems;
- problems = 0;
- pchOrg = getenv("organization");
- pchName = getenv("name");
- puts("#\tThis is a shell archive.");
- puts("#\tRemove everything above and including the cut line.");
- puts("#\tThen run the rest of the file through sh.");
- puts("#----cut here-----cut here-----cut here-----cut here----#");
- puts("#!/bin/sh");
- puts("# shar: Shell Archiver");
- puts("#\tRun the following text with /bin/sh to create:");
- for (ppchList = ppchFiles; *ppchList; ++ppchList)
- printf("#\t%s\n", *ppchList);
- stime(clock);
- printf("# This archive created: %s",clock);
- if (pchName)
- printf("# By:\t%s (%s)\n", pchName,pchOrg);
- return(0);
- }
-
-
- /* create an ASCII time string and copy it into timeline. Caller
- * should make sure timeline has ~35 characters space.
- */
- stime(timeline)
- char timeline[];
- {
- register int mytime;
- register int date;
- register int hours, minutes, seconds;
- int day, month, year;
- static char *months[] = {"January","February","March","April",
- "May","June","July","August","September",
- "October","November","December"};
- char *tzone;
- tzone = getenv("timezone");
- mytime = Tgettime();
- date = Tgetdate();
- seconds = (mytime&31)*2;
- minutes = (mytime>>5)&63;
- hours = (mytime>>11)&31;
- day = (date&31);
- month = ((date>>5)&15)-1;
- year = ((date>>9)&31)+1980;
- sprintf(timeline,"%02d-%s-%d %d:%02d:%02d %s\n",
- day,months[month],year,hours,minutes,seconds,tzone);
- return(1);
- }
-
-
- int
- archive(input, output)
- char *input, *output;
- {
- char line[BUFSIZ];
- register FILE *ioptr;
-
- if (ioptr = fopen(input, "r")) {
- printf("%s << \\%s > %s\n", Filter, Delim, output);
- while(fgets(line, BUFSIZ, ioptr)) {
- if (Prefix)
- fputs(Prefix, stdout);
- fputs(line, stdout);
- if (Count)
- fsize += strlen(line);
- }
- puts(Delim);
- fclose(ioptr);
- return(0);
- }
- else {
- fprintf(stderr, "shar: Can't open '%s'\n", input);
- return(1);
- }
- }
-
-
- void shar(file)
- char *file;
- {
- register char *basefile;
- basefile = file;
- if (!strcmp(file, "."))
- return;
- fsize = 0;
- if (Basename) {
- while(*basefile)
- basefile++; /* go to end of name */
- while(basefile > file && *(basefile-1) != '/')
- basefile--;
- }
- if (Verbose)
- printf("echo shar: extracting %s\n", basefile);
- if (archive(file, basefile))
- exit(66);
- if (Count) {
- printf("if test %ld -ne \"`wc -c %s`\"\n",fsize,basefile);
- printf("then\necho shar: error transmitting %s ",basefile);
- printf("'(should have been %ld characters)'\nfi\n",fsize);
- }
- }
-
-
- getpat(pattern)
- char *pattern;
- {
- register char *ptr;
-
- ptr = pattern;
- sav[savind] = malloc(strlen(ptr)+1);
- strcpy(sav[savind++],ptr);
- if (access(ptr,4)) {
- printf("No read access for file: %s\n",ptr);
- return(-1);
- }
- return(0);
- }
-
-
- /*
- * get option letter from argument vector
- */
- int
- getopt(nargc, nargv, ostr)
- int nargc;
- char **nargv, *ostr;
- {
- register char *oli; /* option letter list index */
- static char *place = EMSG; /* option letter processing */
-
- if(!*place) { /* update scanning pointer */
- if(optind >= nargc || *(place = nargv[optind])
- != '-' || !*++place)
- return(EOF);
- if (*place == '-') { /* found "--" */
- ++optind;
- return(EOF);
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':'
- || !(oli = index(ostr,optopt))) {
- if(!*place)
- ++optind;
- tell(": illegal option");
- }
- if (oli) { /* %$^& what if oli = NULL!!! */
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- }
- else { /* need an argument */
- if (*place) /* no white space */
- optarg = place;
- else {
- if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- tell(": option requires an argument");
- }
- else
- optarg = nargv[optind]; /*white space*/
- }
- place = EMSG;
- ++optind;
- }
- }
- return(optopt); /* dump back option letter */
- }
-
-
- int
- getarg(nargc, nargv)
- int nargc;
- char **nargv;
- {
- if (nargc <= optind) {
- optarg = (char *) 0;
- return(EOF);
- }
- else {
- optarg = nargv[optind++];
- return 0;
- }
- }
-
-
- dounshar(ArcNam)
- char *ArcNam;
- {
- register int i;
- register FILE *inptr,*outptr;
- register int hundreds;
- char line[BUFSIZ];
- int DirNum = -1;
- int Prefix = 0;
- char Dirs[10][40], FilNam[428], Delim[128], ScrStr[28];
- char strip[40];
- char *ptr, *lptr;
- int wipeold, append, exists;
- struct stat dirstat;
-
- if (!(inptr = fopen(ArcNam,"r"))) {
- fprintf(stderr,"shar: Can't open archive '%s'\n", ArcNam);
- return;
- }
- while (fgets(line, BUFSIZ, inptr)) {
- for (lptr = line; (*lptr != (char) 0) && (isspace(*lptr));
- lptr++)
- ;
- if (strncmp(lptr, "sed ", 4) == 0) {
- Prefix = 0;
- strcpy(strip, "");
- if (!(ptr = index(lptr,'/')))
- goto getfil;
- if (*++ptr == '^')
- ++ptr;
- while (*ptr != '/') {
- strncat(strip, ptr, 1);
- Prefix++;
- *(strip + Prefix) = (char) 0;
- ptr++;
- }
- goto getfil;
- }
- else if (strncmp(lptr, "gres ", 5) == 0) {
- Prefix = 0;
- strcpy(strip, "");
- if (!(ptr = index(lptr,'\'')))
- goto getfil;
- if (*++ptr == '^')
- ++ptr;
- while (*ptr != '\'') {
- if (*ptr == '0')
- continue;
- strncat(strip, ptr, 1);
- Prefix++;
- *(strip + Prefix) = (char) 0;
- ptr++;
- }
- goto getfil;
- }
- else if (strncmp(lptr,"cat ",4) == 0) {
- Prefix = 0;
- getfil:
- FilNam[0] = 0;
-
- for (i = 0; i <= DirNum; i++) {
- strcat(FilNam,Dirs[i]);
- strcat(FilNam,"\\");
- }
-
- append = 0;
- getshpar(lptr, ">", ScrStr, 1);
- if (strcmp(">", ScrStr) == 0) {
- getshpar(lptr, ">>", ScrStr, 1);
- append = 1;
- }
- strcat(FilNam,ScrStr);
- getshpar(lptr, "<<", Delim, 0);
- wipeold = 1;
- exists = 1;
-
- i = stat(FilNam, &dirstat);
- i = i < 0 ? i : (int) dirstat.st_mode;
- if ((i >= 0) && (i <= 0X3F)) {
- if (!OverWrite)
- wipeold = 0;
- }
- else
- exists = 0;
-
- if (wipeold && !append) {
- outptr = fopen(FilNam, "w");
- fprintf(stderr, "Creating %s ", FilNam);
- }
- else if (append && exists) {
- outptr = fopen(FilNam, "a");
- fprintf(stderr, "Appending %s ", FilNam);
- }
- else if (append && !exists) {
- fprintf(stderr, "Cannot append to %s,\n\
- \tyou need to unshar another sharchive first ", FilNam);
- }
- else
- fprintf(stderr, "Will not overwrite %s ",
- FilNam);
- if (!outptr) {
- fprintf(stderr, "Fatal: could not open file \
- %s\n", FilNam);
- exit(1);
- }
- fflush(stderr);
- hundreds = 0;
- while (fgets(line, BUFSIZ, inptr)) {
- if (strncmp(line, Delim, strlen(Delim)) == 0)
- break;
- hundreds++;
- if (!(hundreds % 100)) {
- fprintf(stderr, ".");
- fflush(stderr);
- }
- if ((wipeold && !append) || (append && exists))
- if (strncmp(line, strip, Prefix))
- fputs(line, outptr);
- else
- fputs(&line[Prefix],outptr);
- }
- if (outptr) {
- fclose(outptr);
- fprintf(stderr,"done\n");
- }
- else {
- fprintf(stderr," error in creating file\n");
- exit(1);
- }
- }
- else if (strncmp(lptr, "mkdir ", 6) == 0) {
- FilNam[0] = 0;
-
- for (i = 0; i <= DirNum; i++) {
- strcat(FilNam,Dirs[i]);
- strcat(FilNam,"\\");
- }
-
- getshpar(lptr, "mkdir", ScrStr, 1);
- strcat(FilNam, ScrStr);
-
- i = stat(FilNam, &dirstat);
- i = i < 0 ? i : (int) dirstat.st_mode;
- if ((i >= 0) && (i <= 0X3F))
- if ((i & 0X10) == 0X10)
- continue; /* don't re-create */
- else {
- fprintf(stderr, "will not mkdir %s,\n\
- \tthere is already a file of that name\n", FilNam);
- exit(1);
- }
- if (Dcreate(FilNam)) {
- fprintf(stderr, "could not mkdir %s\n", FilNam);
- exit(1);
- }
- }
- else if (strncmp(lptr,"cd ",3) == 0) {
- if (lptr[3] == '.' && lptr[4] == '.')
- DirNum--;
- else if (DirNum >= 9)
- fprintf(stderr,"directories nested too deep\n");
- else {
- DirNum++;
- getshpar(lptr, "cd", ScrStr, 1);
- strcpy(Dirs[DirNum], ScrStr);
- }
- if (DirNum < -1)
- DirNum = -1;
- }
- else if (strncmp(lptr, "chdir ", 6) == 0) {
- if (lptr[6] == '.' && lptr[7] == '.')
- DirNum--;
- else if (DirNum >= 9)
- fprintf(stderr,"directories nested too deep\n");
- else {
- DirNum++;
- getshpar(lptr, "cd", ScrStr, 1);
- strcpy(Dirs[DirNum], ScrStr);
- }
- if (DirNum < -1)
- DirNum = -1;
- }
- }
- fclose(inptr);
- }
-
-
- getshpar(line, sea, par, flipslash)
- char *line, *sea, *par;
- int flipslash;
- {
- register char *scr1, *scr2;
-
- while (*line) {
- scr1 = line;
- scr2 = sea;
- while (*scr1 && *scr2 && *scr1 == *scr2) {
- scr1++;
- scr2++;
- }
- if (*scr2 == 0) {
- if (*scr1 == 0) {
- *par = 0;
- return;
- }
- while (*scr1 == ' ' || *scr1 == '\t' ||
- *scr1 == '\\' || *scr1 == '\'' ||
- *scr1 == '"')
- scr1++;
- while (*scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
- *scr1 != '\\' && *scr1 != '\'' &&
- *scr1 != '"' && *scr1 != '\n' &&
- *scr1 != '\r') {
- if ((*scr1 == '/') && flipslash) {
- *par++ = '\\';
- scr1++;
- }
- else
- *par++ = *scr1++;
- }
- if (*(par - 1) == '\\') /* if \ at end, not ST path */
- par--;
- *par = 0;
- return;
- }
- line++;
- }
- *par = 0;
- }
-
-
- /* since nothing ever initializes the environment table on the ST
- * I'll just use my home brew cc.ini environment file.
- */
- char *getenv(var)
- register char *var;
- {
- FILE *fp;
- register char *ptr;
- static char line[81];
- register char *safestore;
-
- if ((fp=fopen("cc.ini","r")) == NULL)
- return(Defenv);
- while (fgets(line,80,fp)) {
- if ((ptr=index(line,' '))!=(char *)NULL)
- *ptr = '\0';
- if ((ptr=index(line,'\n'))!=(char *)NULL)
- *ptr = '\0';
- if ((ptr=index(line,'\t'))!=(char *)NULL)
- *ptr = '\0';
- if ((ptr=index(line,'='))!=(char *)NULL)
- *ptr = '\0';
- else
- continue;
- ++ptr;
- if (strcmp(line, var) == 0) {
- safestore = malloc(strlen(ptr)+1);
- strcpy(safestore,ptr);
- return(safestore);
- }
- else if (feof(fp))
- break;
- }
- return(Defenv);
- }
-